#ifndef YOOHOO_XMPPCORE_SASLNEGOTIANT_H
#define YOOHOO_XMPPCORE_SASLNEGOTIANT_H

#include "xmppcore/negotiant.h"

#include <QtCrypto>
#include <QtNetwork/QAbstractSocket>
#include <QtCore/QPointer>

namespace yoohoo_xmppcore {

class SaslNegotiant : public Negotiant {
	Q_OBJECT
public:
	enum SaslNegotiantState {
		None,
		AuthMechanismSent,
		ChallengeReceived,
		ResponseSent,
		AbortSent,
		AbortedReceived,
		AuthenticationSuccess,
		AuthenticationFailure,
		AuthenticationError,
		NegotiationFinished
	};
	enum SaslError {
		SaslErrorNotSupported,
		SaslErrorInit,
		SaslErrorHandshake,
		SaslErrorCrypt,
		SaslErrorUnknown,
		SaslErrorAborted,
		SaslErrorIncorrectEncoding,
		SaslErrorInvalidAuthzid,
		SaslErrorInvalidMechanism,
		SaslErrorMechanismTooWeak,
		SaslErrorNotAuthorized,
		SaslErrorTemporaryAuthFailure
	};
	SaslNegotiant(Connector* connector, QString userName, QString password,
                        QString host, QString realm = QString(), QObject* parent = 0);
	~SaslNegotiant();
	void negotiate();

signals:
	void success();
	void saslError(SaslNegotiant::SaslError error);

protected slots:
		void connectorReceived(QString xml);

protected:
	StreamFeatures* createStreamFeatures();

private slots:
	void saslClientStarted(bool clientInit, const QByteArray& clientInitData);
	void saslNextStep(const QByteArray& stepData);
	void saslNeedParams(const QCA::SASL::Params& params);
	void processSaslError();
	void processSocketError(QAbstractSocket::SocketError error);

private:
	void createSasl();
	void destroySasl();
	bool processChallenge(QString& xml, QByteArray& challenge);
	QString createResponseXml(const QByteArray& response);
	QString saslAuthConditionToString(QCA::SASL::AuthCondition x);

private:
	SaslNegotiantState _saslNegotiationState;
	QPointer<QCA::SASL> _sasl;
	QString _userName;
	QString _password;
	QString _realm;
	int _waitCycles;
	QAbstractSocket::SocketError _socketError;
	bool _socketDone;
	QString _host;
};

}

#endif
